import os
import sys
from copy import deepcopy
from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, 
                             QComboBox, QFileDialog, QTableWidget, QTableWidgetItem, 
                             QHeaderView, QMessageBox, QLineEdit, QToolButton, QSplitter,
                             QApplication, QGroupBox, QTextEdit, QCheckBox)
from PyQt6.QtCore import Qt, pyqtSignal
from PyQt6.QtGui import QColor, QPalette
import pandas as pd
from docx import Document
from docx.enum.text import WD_BREAK
import traceback

class BatchReplaceWindow(QWidget):
    """批量替换的界面"""
    
    # 定义信号
    status_signal = pyqtSignal(str)
    closed = pyqtSignal()  # 窗口关闭信号
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self.parent = parent
        self._excel_data = None
        self.output_dir = ""
        self.file_type = "WORD"
        self.template_file = ""
        
        # 设置窗口属性
        self.setWindowTitle("批量替换")
        self.resize(800, 600)
        
        self.init_ui()
        
    def init_ui(self):
        """初始化界面"""
        # 创建主布局
        main_layout = QHBoxLayout(self)
        
        # 创建分割器
        splitter = QSplitter(Qt.Orientation.Horizontal)
        
        # 左侧操作窗体
        left_widget = QWidget()
        left_layout = QVBoxLayout(left_widget)
        
        # 导入Excel区域
        excel_group = QGroupBox("导入Excel (支持Excel数据写入WORD模板)")
        excel_layout = QVBoxLayout(excel_group)
        
        excel_button = QPushButton("导入Excel")
        excel_button.setStyleSheet("background-color: #00B19D; color: white; padding: 8px;")
        excel_button.clicked.connect(self.import_excel)
        excel_layout.addWidget(excel_button)
        
        clear_button = QPushButton("清空列表")
        clear_button.clicked.connect(self.clear_excel_data)
        excel_layout.addWidget(clear_button)
        
        # 添加显示待替换参数的文本框
        self.params_text = QTextEdit()
        self.params_text.setReadOnly(True)
        self.params_text.setPlaceholderText("导入Excel后将显示待替换的参数...")
        self.params_text.setMaximumHeight(100)
        excel_layout.addWidget(self.params_text)
        
        left_layout.addWidget(excel_group)
        
        # 模板设置区域
        template_group = QGroupBox("模板设置")
        template_layout = QVBoxLayout(template_group)
        
        template_layout.addWidget(QLabel("文件类型"))
        self.file_type_combo = QComboBox()
        self.file_type_combo.addItems(["WORD", "EXCEL", "PDF", "PPT", "txt"])
        self.file_type_combo.currentTextChanged.connect(self.on_file_type_changed)
        template_layout.addWidget(self.file_type_combo)
        
        self.template_button = QPushButton("选择模板文件")
        self.template_button.clicked.connect(self.select_template)
        template_layout.addWidget(self.template_button)
        
        left_layout.addWidget(template_group)
        
        # 输出设置区域
        output_group = QGroupBox("输出设置")
        output_layout = QVBoxLayout(output_group)
        
        # 添加合并选项
        self.merge_checkbox = QCheckBox("全部输出到一个文件")
        self.merge_checkbox.setChecked(False)
        output_layout.addWidget(self.merge_checkbox)
        
        output_dir_layout = QHBoxLayout()
        self.output_dir_edit = QLineEdit()
        self.output_dir_edit.setReadOnly(True)
        output_dir_layout.addWidget(self.output_dir_edit)
        
        self.browse_button = QToolButton()
        self.browse_button.setText("...")
        self.browse_button.clicked.connect(self.select_output_dir)
        output_dir_layout.addWidget(self.browse_button)
        
        output_layout.addWidget(QLabel("输出目录"))
        output_layout.addLayout(output_dir_layout)
        
        self.open_dir_button = QPushButton("打开输出目录")
        self.open_dir_button.clicked.connect(self.open_output_dir)
        self.open_dir_button.setEnabled(False)
        output_layout.addWidget(self.open_dir_button)
        
        left_layout.addWidget(output_group)
        
        # 执行按钮
        self.execute_button = QPushButton("立即执行")
        self.execute_button.setStyleSheet("background-color: #FF9F43; color: white; padding: 10px; font-weight: bold;")
        self.execute_button.clicked.connect(self.execute_batch_replace)
        self.execute_button.setEnabled(False)
        left_layout.addWidget(self.execute_button)
        
        # 返回按钮
        back_button = QPushButton("返回主界面")
        back_button.clicked.connect(self.back_to_main)
        left_layout.addWidget(back_button)
        
        # 右侧预览窗体
        right_widget = QWidget()
        right_layout = QVBoxLayout(right_widget)
        
        # 添加表格
        self.table = QTableWidget(0, 3)  # 3列：名称、状态、操作
        self.table.setHorizontalHeaderLabels(["名称", "状态", "操作"])
        self.table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
        
        # 设置表格为只读模式
        self.table.setEditTriggers(QTableWidget.EditTrigger.NoEditTriggers)
        self.table.setSelectionMode(QTableWidget.SelectionMode.NoSelection)
        self.table.setFocusPolicy(Qt.FocusPolicy.NoFocus)
        
        right_layout.addWidget(self.table)
        
        # 添加到分割器
        splitter.addWidget(left_widget)
        splitter.addWidget(right_widget)
        splitter.setSizes([200, 400])  # 设置初始大小
        
        # 添加到主布局
        main_layout.addWidget(splitter)
        
    def import_excel(self):
        """导入Excel文件"""
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择Excel文件", "", "Excel Files (*.xlsx *.xls)"
        )
        if file_path:
                df = pd.read_excel(file_path)
                # 检查列名是否符合 {替换内容X} 格式
                valid_columns = [col for col in df.columns if col.startswith('{') and col.endswith('}')]
                if len(valid_columns) == 0:
                    raise ValueError("Excel文件中没有找到符合 {替换内容X} 格式的列名")
                self._excel_data = df[valid_columns]
                self.populate_table()
                self.update_execute_button()
                
                # 更新待替换参数显示
                params_text = "待替换参数：\n" + "\n".join(valid_columns)
                self.params_text.setText(params_text)
                

    def clear_excel_data(self):
        """清空导入的Excel数据"""
        self._excel_data = None
        self.table.setRowCount(0)
        self.params_text.clear()
        self.update_execute_button()
        QMessageBox.information(self, "成功", "Excel数据已清空！")
                
    def on_file_type_changed(self, file_type):
        """文件类型改变时更新UI"""
        self.file_type = file_type
        self.template_file = ""  # 重置模板文件
        self.update_execute_button()
        
    def select_template(self):
        """选择模板文件"""
        file_filter = self.get_file_filter()
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择模板文件", "", file_filter
        )
        if file_path:
            self.template_file = file_path
            self.update_execute_button()
            
    def get_file_filter(self):
        """根据文件类型返回文件过滤器"""
        if self.file_type == "WORD":
            return "Word Files (*.docx *.doc)"
        elif self.file_type == "EXCEL":
            return "Excel Files (*.xlsx *.xls)"
        elif self.file_type == "PDF":
            return "PDF Files (*.pdf)"
        elif self.file_type == "PPT":
            return "PowerPoint Files (*.pptx *.ppt)"
        elif self.file_type == "txt":
            return "Text Files (*.txt)"
        else:
            return "All Files (*.*)"
        
    def select_output_dir(self):
        """选择输出目录"""
        dir_path = QFileDialog.getExistingDirectory(self, "选择输出目录")
        if dir_path:
            self.output_dir = dir_path
            self.output_dir_edit.setText(dir_path)
            self.open_dir_button.setEnabled(True)
            self.update_execute_button()
            
    def open_output_dir(self):
        """打开输出目录"""
        if self.output_dir:
            os.startfile(self.output_dir)
            
    def populate_table(self):
        """填充表格"""
        if self._excel_data is None:
            return
        
        self.table.setRowCount(len(self._excel_data))
        for i, (_, row) in enumerate(self._excel_data.iterrows()):
            # 使用第一列作为显示名称，如果是替换内容格式则去掉大括号
            display_name = str(row.iloc[0])
            if display_name.startswith('{') and display_name.endswith('}'):
                display_name = display_name[1:-1]
            self.table.setItem(i, 0, QTableWidgetItem(display_name))
            self.table.setItem(i, 1, QTableWidgetItem("待处理"))
            delete_button = QPushButton("删除")
            delete_button.clicked.connect(lambda _, row=i: self.delete_row(row))
            self.table.setCellWidget(i, 2, delete_button)
            
    def delete_row(self, row):
        """删除表格行"""
        try:
            # 如果是最后一条数据，直接清空表格
            if self.table.rowCount() == 1:
                self.table.setRowCount(0)
                self._excel_data = None
                self.params_text.clear()
            else:
                # 删除指定行
                self.table.removeRow(row)
                # 更新Excel数据
                if self._excel_data is not None and not self._excel_data.empty:
                    self._excel_data = self._excel_data.drop(self._excel_data.index[row]).reset_index(drop=True)

            # 更新按钮状态
            self.update_execute_button()
            # 强制刷新表格
            self.table.repaint()
            QApplication.processEvents()

        except Exception as e:
            QMessageBox.critical(self, "错误", f"删除行时出错: {str(e)}")
            import traceback
            traceback.print_exc()
        
    def update_execute_button(self):
        """更新执行按钮状态"""
        should_enable = (
            self._excel_data is not None and
            not self._excel_data.empty and
            self.output_dir != "" and
            (self.file_type == "文件夹" or self.template_file != "")
        )
        self.execute_button.setEnabled(should_enable)
        
    def execute_batch_replace(self):
        """执行批量替换"""
        if self._excel_data is None or self.template_file == "" or self.output_dir == "":
            QMessageBox.warning(self, "警告", "请确保已选择Excel文件、模板文件和输出目录")
            return

        try:
            # 获取Excel数据
            df = self._excel_data

            # 更新状态
            for i in range(self.table.rowCount()):
                self.table.setItem(i, 1, QTableWidgetItem("处理中..."))
                self.table.repaint()  # 强制更新UI

            success_count = 0
            fail_count = 0

            try:
                # 验证模板文件
                template_test = Document(self.template_file)
            except Exception as e:
                QMessageBox.critical(self, "错误", f"无法读取Word模板文件：{str(e)}\n请确保模板文件格式正确且未被其他程序占用。")
                return

            # 为每行数据生成独立文档
            for index, row in df.iterrows():
                try:
                    # 加载模板文件
                    template_doc = Document(self.template_file)

                    # 准备替换数据字典
                    replace_data = {col: str(row[col]) if pd.notna(row[col]) else "" for col in df.columns}
                    
                    # 替换段落中的占位符
                    print("\n[DEBUG] 开始替换段落中的占位符")
                    for paragraph in template_doc.paragraphs:
                        for col, value in replace_data.items():
                            if col in paragraph.text:
                                print(f"[DEBUG] 在段落中找到占位符: {col}")
                                if not self.replace_text_keeping_format(paragraph, col, value):
                                    print(f"[DEBUG] 警告: 未能成功替换占位符 {col}")
                    
                    # 替换表格中的占位符
                    print("\n[DEBUG] 开始替换表格中的占位符")
                    for table in template_doc.tables:
                        for table_row in table.rows:
                            for cell in table_row.cells:
                                for paragraph in cell.paragraphs:
                                    for col, value in replace_data.items():
                                        if col in paragraph.text:
                                            print(f"[DEBUG] 在表格单元格中找到占位符: {col}")
                                            if not self.replace_text_keeping_format(paragraph, col, value):
                                                print(f"[DEBUG] 警告: 未能成功替换表格中的占位符 {col}")
                    
                    # 替换页眉页脚中的占位符
                    for section in template_doc.sections:
                        for paragraph in section.header.paragraphs:
                            for col, value in replace_data.items():
                                if col in paragraph.text:
                                    self.replace_text_keeping_format(paragraph, col, value)
                        for paragraph in section.footer.paragraphs:
                            for col, value in replace_data.items():
                                if col in paragraph.text:
                                    self.replace_text_keeping_format(paragraph, col, value)

                    # 生成文件名
                    file_name_base = str(row.iloc[0]).strip()
                    if file_name_base.startswith('{') and file_name_base.endswith('}'):
                        file_name_base = file_name_base[1:-1]
                    
                    # 清除文件名中的非法字符
                    invalid_chars = ['/', '\\', ':', '*', '?', '"', '<', '>', '|']
                    for char in invalid_chars:
                        file_name_base = file_name_base.replace(char, '_')
                    
                    # 如果是合并模式，添加到合并文档；否则单独保存
                    if self.merge_checkbox.isChecked():
                        print(f"[DEBUG] 合并模式处理第 {index+1} 条数据")
                        if index == 0:  # 第一次创建合并文档
                            print("[DEBUG] 创建合并文档")
                            merged_doc = deepcopy(template_doc)
                        else:
                            print("[DEBUG] 添加分节符和内容")
                            # 添加分节符
                            merged_doc.add_paragraph()
                            # 复制内容到合并文档
                            for element in template_doc.element.body:
                                merged_doc.element.body.append(deepcopy(element))
                    else:
                        # 单独保存文档
                        output_file = os.path.join(self.output_dir, f"{file_name_base}.docx")
                        template_doc.save(output_file)
                        print(f"[DEBUG] 已保存单独文件: {output_file}")

                    # 更新表格状态
                    self.table.setItem(index, 1, QTableWidgetItem("已完成"))
                    success_count += 1
                except Exception as e:
                    error_msg = f"处理第 {index+1} 行时出错：\n{str(e)}"
                    self.table.setItem(index, 1, QTableWidgetItem(f"失败: {str(e)}"))
                    QMessageBox.warning(self, "错误", error_msg)
                    fail_count += 1

            # 如果是合并模式，保存合并后的文档
            if self.merge_checkbox.isChecked() and success_count > 0:
                merged_file = os.path.join(self.output_dir, f"合并文档.docx")
                merged_doc.save(merged_file)
                print(f"[DEBUG] 已保存合并文件: {merged_file}")
                
            QMessageBox.information(self, "完成", 
                                  f"批量替换已完成\n成功: {success_count}\n失败: {fail_count}\n" + 
                                  f"输出目录: {self.output_dir}")
        except Exception as e:
            error_msg = f"批量替换过程中出错：\n{str(e)}"
            QMessageBox.critical(self, "错误", error_msg)

    def replace_text_keeping_format(self, paragraph, placeholder, new_text):
        """替换文本并保留原有格式"""
        if placeholder not in paragraph.text:
            print(f"[DEBUG] 占位符 {placeholder} 未在段落中找到")
            return False

        print(f"[DEBUG] 开始替换: {placeholder} -> {new_text}")
        
        # 情况1：占位符完整存在于单个run中
        for run in paragraph.runs:
            if placeholder in run.text:
                print(f"[DEBUG] 在run中找到完整占位符: {run.text}")
                font = run.font
                run.text = run.text.replace(placeholder, new_text)
                # 保留原有格式
                run.font.name = font.name
                run.font.size = font.size
                run.font.bold = font.bold
                run.font.italic = font.italic
                run.font.underline = font.underline
                run.font.color.rgb = font.color.rgb
                return True
        
        # 情况2：占位符跨多个run
        print(f"[DEBUG] 尝试处理跨run的占位符: {placeholder}")
        full_text = ''.join(run.text for run in paragraph.runs)
        if placeholder in full_text:
            print(f"[DEBUG] 确认占位符存在于合并文本中")
            
            # 清除所有run
            for run in paragraph.runs:
                run.text = ""
            
            # 在第一个run中插入替换后的文本
            paragraph.runs[0].text = full_text.replace(placeholder, new_text)
            
            # 保留第一个run的格式
            if paragraph.runs:
                first_run = paragraph.runs[0]
                first_run.font.name = paragraph.runs[-1].font.name
                first_run.font.size = paragraph.runs[-1].font.size
                first_run.font.bold = paragraph.runs[-1].font.bold
                first_run.font.italic = paragraph.runs[-1].font.italic
                first_run.font.underline = paragraph.runs[-1].font.underline
                first_run.font.color.rgb = paragraph.runs[-1].font.color.rgb
            
            return True
        
        print(f"[DEBUG] 警告: 无法替换占位符 {placeholder}")
        return False
       
    def back_to_main(self):
        """返回主界面"""
        self.closed.emit()  # 先发送信号
        self.close()  # 再关闭窗口
        
    def closeEvent(self, event):
        """重写关闭事件，确保点击X按钮时也返回主界面"""
        self.closed.emit()
        event.accept()
